

const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z]*`;
const qnameCapture = `((?:${ncname}\\:)?${ncname})`;
const startTagOpen = new RegExp(`^<${qnameCapture}`); // 标签开头的正则 捕获的内容是标签名
const endTag = new RegExp(`^<\\/${qnameCapture}[^>]*>`); // 匹配闭合标签 </div>
const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/; // 匹配属性的
const startTagClose = /^\s*(\/?)>/; // 匹配标签结束的 >


function createAstElement (tagName, attrs) {
  return {
    tagName,
    type: 1,
    parent: null,
    children: [],
    attrs
  }
}
let root;
let stack = []

function start (tagName, attrs) {
  let parent = stack[stack.length - 1]
  let element = createAstElement(tagName, attrs)
  if (!root) {
    root = element
  }

  if (parent) {
    element.parent = parent
    parent.children.push(element)
  }
  stack.push(element)
}
function end (tagName) {
  let last = stack.pop()
  if (tagName !== last.tag) {
    // throw new Error('闭合有误')
  }
}
function chars (text) {
  text = text.replace(/\s/g, '')
  if (text) {
    let parent = stack[stack.length - 1]
    parent.children.push({
      type: 3,
      text
    })
  }
}
export function parserHTML (html) {
  // 去掉解析完的
  function advance (len) {
    html = html.substring(len)
  }
  // 解析开始标签
  function parseStartTag () {
    const start = html.match(startTagOpen)
    if (start) {
      const match = {
        tagName: start[1],
        attrs: []
      }
      advance(start[0].length)

      let end;
      let attr;
      // 没有遇到标签结尾 不停的循环 找属性
      while (!(end = html.match(startTagClose)) && (attr = html.match(attribute))) {
        match.attrs.push({ name: attr[1], value: attr[3] || attr[4] || attr[5] })
        advance(attr[0].length)
      }
      if (end) {
        advance(end[0].length)
      }
      return match
    }
    return false //不是开始标签
  }
  // 循环一直解析html  直至解析完
  while (html) {//  <div id="app">123</div>
    let textEnd = html.indexOf('<')
    if (textEnd == 0) {
      const startTagMatch = parseStartTag(html)
      if (startTagMatch) {
        start(startTagMatch.tagName, startTagMatch.attrs)
        continue
      }
      const endTagMatch = html.match(endTag)
      if (endTagMatch) {
        // console.log(endTagMatch, 'endTagMatch')
        end(endTagMatch[1])
        advance(endTagMatch[0].length)
        continue
      }

      // const endTagMatch = parseEndTag()
      // if (endTagMatch) {

      // }
    }
    let text;//123</div>
    if (textEnd > 0) {
      text = html.substring(0, textEnd)
    }
    if (text) {
      chars(text)
      advance(text.length)
    }

  }
  // root  树
  return root
}